package com.hmall.gateway.routers;

import cn.hutool.json.JSONUtil;
import com.alibaba.cloud.nacos.NacosConfigManager;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import com.hmall.common.utils.CollUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;

import javax.annotation.PostConstruct;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Executor;

/**
 * 动态路由加载
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class DynamicRouterLoad {

    //只要我们拿到Nacos中 ConfigManager就等于拿到了ConfigService
    private final NacosConfigManager nacosConfigManager;
    //利用RouteDefinitionWriter来更新路由表
    private final RouteDefinitionWriter writer;
    private final String dataId ="gateway-routes.json";
    private final String group ="DEFAULT_GROUP";

    //用来存储路由表中的路由id
    private final Set<String> routerIds=new HashSet<>();

    @PostConstruct  //在这个bean（DynamicRouterLoad）类执行完后执行
    public void initRoutConfigListener() throws NacosException {
        // 1.注册监听器并首次拉取配置
        String configInfo = nacosConfigManager.getConfigService()
                .getConfigAndSignListener(dataId, group, 5000, new Listener() {
                    @Override
                    public Executor getExecutor() {
                        return null;
                    }
                    /**
                     * 路由变更
                     * @param
                     */
                    @Override
                    public void receiveConfigInfo(String configInfo) {
                      updateConfigInfo(configInfo);
                    }
                });
        //2.首次拉取路由信息时，需要保存路由配置
        updateConfigInfo(configInfo);
    }

    /**
     * 对路由表进行处理
     * @param configInfo
     */
    public void updateConfigInfo(String configInfo){
        log.debug("监听到路由配置变更，{}", configInfo);
        //1.解析nacos配置列表中的gateway-routes.json文件。
        // 并将其转为RouteDefinition类型
        List<RouteDefinition> routeDefinitions = JSONUtil.toList(configInfo, RouteDefinition.class);
        //2.利用RouteDefinitionWriter删除旧的路由表
        for (String routerId : routerIds) {
            //响应式，需要订阅
            writer.delete(Mono.just(routerId)).subscribe();
        }
        //清空Set集合
        routerIds.clear();
        // 2.2.判断是否有新的路由要更新
        if (CollUtils.isEmpty(routeDefinitions)) {
            // 无新路由配置，直接结束
            return;
        }
        //3.保存路由信息
        for (RouteDefinition routeDefinition : routeDefinitions) {
            //3.1更新路由
            writer.save(Mono.just(routeDefinition)).subscribe();
            //3.2记录路由的id
            routerIds.add(routeDefinition.getId());
        }

    }
}
